import holoviews as hv
hv.extension('bokeh')
import numpy as np
import scipy.signal
2. Espectro y Transformada de Fourier¶
2.1. Espectro de frecuencia¶
2.1.1. Breve historia¶
Isaac Newton llamó espectros a los componentes que forman la luz blanca y que normalmente no se pueden ver
Newton mostró usando prismas que la luz blanca puede descomponerse en colores y viceverza
Hoy entendemos que la luz como onda tiene una frecuencia asociada y que cada color es una frecuencia particular
|
|
Paradójicamente, Newton nunca acepto que esto se debía a la frecuencia de la radiación ya que creía en la teoría corpuscular de la luz
2.1.2. Ondas y señales sinusoidales¶
Una onda es una perturbación que transporta energía a través del espacio
Tipicamente se describe por su frecuencia, amplitud y desfase. La frecuencia (Hertz) es el recíproco del período (segundos)
La siguiente es una función del tiempo completamente descrita por su amplitud \(A\), frecuencia \(f\) (período \(P=1/f\)) y fase \(\phi\)
Observe en el siguiente ejemplo como cambia la señal al modificar sus parámetros
def wave(time, frequency, phase, amplitude):
return amplitude*np.cos(2.0*np.pi*time*frequency + phase)
signal_plot = hv.HoloMap(kdims=['Amplitud', 'Frecuencia', 'Desfase'])
t = np.linspace(0, 2, num=1000)
for A in [0.5, 1.]:
for f in [0.5, 1, 2]:
for phi in np.arange(0., np.pi, np.pi/10):
signal_plot[(A, f, phi)] = hv.Curve((t, wave(t, f, phi, A)))
signal_plot.opts(hv.opts.Curve(width=500, height=300))
2.1.3. Componentes frecuenciales y descomposiciones armónicas¶
Una sinusoide que es períodica en una fracción
también es periódica en \(P\)
En general llamamos a
\(f_0 = 1/P\) la frecuencia fundamental
\(f_k = k/P = kf_0\) el k-esimo armónico de \(f_0\)
Si sumamos armónicos con distintas amplitudes el resultado es una nueva función periódica que tiene la misma frecuencia fundamental
En el siguiente ejemplo modifique las amplitudes de cada armónico y observe la señal resultante
Note que la suma de tres sinusoides no es necesariamente otra sinusoide
t = np.linspace(0, 2, num=1000)
def my_signal(time, frequency, Amplitudes):
s = 0
for k, A in enumerate(Amplitudes):
s += A*np.cos(2.0*np.pi*time*(k+1)*frequency)
return s
signal_plot = hv.HoloMap(kdims=['Amplitud fundamental',
'Amplitud 1er armónico',
'Amplitud 2do armónico',
'Frecuencia'])
for f in [1, 2]:
for A1 in [0.5, 1.]:
for A2 in [0, 0.5, 1.]:
for A3 in [0, 0.5, 1.]:
signal_plot[(A1, A2, A3, f)] = hv.Curve((t, my_signal(t, f, [A1, A2, A3])))
signal_plot.opts(hv.opts.Curve(width=500, height=300))
La noción de sintetizar señales en base a sinusoides se generaliza por medio de la serie trigonométrica
donde \(a_k = A_k \cos(\phi_k)\) y \(b_k = -A_k \sin(\phi_k)\) se obtienen de \(\cos(x+y) = \cos(x)\cos(y) - \sin(x)\sin(y)\)
Con esto podemos generar funciones periódicas arbitrarias definiendo \(\{a_k, b_k\}\) y \(f\)
Ejemplo
Sea por ejemplo \(a_k = 0\) y \(b_k = 1/k\) \(\forall k\)
¿Qué señal se obtiene al agregar cada vez más armónicos?
t = np.linspace(0, 5, num=1000)
def trigonometric_series(time, frequency, K):
s = 0
for k in range(1, K):
s += np.sin(2.0*np.pi*time*k*frequency)/(k)
return s
signal_plot = hv.HoloMap(kdims=['Cantidad de armónicos', 'Frecuencia'])
for f in [1, 2]:
for K in [1, 2, 3, 5, 10, 20, 50, 100]:
signal_plot[(K, f)] = hv.Curve((t, trigonometric_series(t, f, K)))
signal_plot.opts(hv.opts.Curve(width=500, height=300))
Nota
Hasta ahora hemos visto como sintetizar señales a partir de sus armónicos, pero también podemos hacer el proceso inverso, es decir encontrar los armónicos de una señal dada
Tal como Newton descompuso la luz blanca en colores, nosotros podemos descomponer una señal en sus armónicos usando la serie de Fourier
2.2. Serie de Fourier¶
Un poco de historia: En 1807 Jean Baptiste Joseph Fourier presenta un teorema indicando que una función periódica arbitraria con periódo \(P=1/f_0\) puede representarse como una suma ponderada de senos y cosenos
La serie de Fourier (FS) es una generalización de la serie trigonométrica a los números complejos. Puede revisar el apéndice de esta lección si necesita refrescar la memoria sobre los números complejos y sus representaciones
La FS se define como
A continuación veremos como obtener los coeficientes de Fourier \(c_k\) para una señal periódicas arbitraria
2.2.1. Base de Fourier¶
El conjunto de funciones
se conoce como base de Fourier y cumple con
La base de Fourier es un conjunto ortonormal en el espacio de funciones periódicas con periódo \(P\). Esto es facilmente comprobable si estudiamos
Podemos usar esta propiedad y escribir el producto punto entre una señal y el m-esimo elemento de la base de Fourier
Esto nos da una forma sencilla para obtener los \(c_m\) de una señal periódica arbitraria
2.2.2. Ejemplo formativo: FS de señal cuadrada¶
Sea
Los coeficientes de su FS son
y
Notemos que a excepción de \(c_0\) los coeficientes sólo tienen parte imaginaria. Además sólo los armónicos impares (senos) son distintos de cero
Finalmente la FS está dada por
Programemos esta expresión y visualicemos el resultado al incrementar cada vez la cantidad de armónicos
t = np.linspace(0, 5, num=1000)
def FS_square(tiempo, frecuencia, K):
s = 0.5 # C_0
for k in range(1, K):
c_k = (1-np.cos(np.pi*k))/(np.pi*k)
s += c_k*np.sin(2.0*np.pi*tiempo*k*frecuencia)
return s
signal_plot = hv.HoloMap(kdims=['Cantidad de armónicos', 'Frecuencia', ])
for f in [1, 2]:
for K in [1, 2, 3, 5, 10, 20, 50, 100]:
signal_plot[(f, K)] = hv.Curve((t, FS_square(t, f, K)))
signal_plot.opts(hv.opts.Curve(width=500, height=300))
2.2.3. Propiedades de la FS¶
A continuación se enumeran algunas de las propiedades más importantes de la FS
Si \(s(t)\) es par entonces \(c_k\) es par
Si \(s(t)\) es impar entonces \(c_k\) es impar
Si \(s(t + P/2) = -s(t)\) (antiperiódica) entonces \(c_k=0\) para k par
Si \(s(t)\) es real y par entonces \(c_k\) es real y par
Si \(s(t)\) es real e impar entonces \(c_k\) es imaginario e impar
La FS es lineal
El Teorema de Parseval relaciona la potencia de una señal periódica arbitraria con sus coeficientes de Fourier
2.3. Transformada de Fourier¶
Podemos extender el concepto de descomposición armónica a señales no periódicas usando la Transformada de Fourier. Esta herramienta matemática será fundamental en este curso
El concepto de frecuencia puede aplicarse también a señales no-periódicas
Según Joseph Fourier una señal no-periódica puede ser vista como una señal periódica con un período infinito
El único requisito es que ahora las frecuencias son un continuo, con un espaciado infinitesimal
A continuación veremos que una señal analógica puede ser vista como continua en el tiempo o continua en frecuencia. En la próxima lección veremos la Transformada de Fourier discreta (DFT) para señales digitales
2.3.1. Derivación de la transformada de Fourier a partir de la FS¶
Sea un tren de pulsos cuadrado con periódo P y ancho \(2T < P\) definido en un período como
Los coeficientes de su serie de Fourier son
y
En el siguiente ejemplo la figura izquierda muestra la señal de pulso cuadrado mientras que la derecha muestra \(c_k\) en función de \(k\)
¿Qué ocurre con \(c_k\) a medida que \(P\) aumenta (\(f\) disminuye)?
def fs_coef(P, T, maxK=200):
K = np.arange(-maxK, maxK)
ck = np.zeros_like(K, dtype='float32')
ck[len(K)//2] = 2*T/P
for k in range(1, K[-1]):
ck[len(K)//2+k] = np.sin(2*np.pi*k*T/P)/(np.pi*k)
ck[len(K)//2-k] = ck[len(K)//2+k]
return K, ck
def synthesis(time, ck, P):
maxK = len(ck)//2
s = ck[maxK]
for k in range(1, maxK):
s += 2*np.cos(2*np.pi*time*k/P)*ck[maxK+k]
return s
t = np.linspace(-3, 3, num=2000)
T = 0.25
signal_plot = hv.HoloMap(kdims=['Periodo'])
fs_plot = hv.HoloMap(kdims=['Periodo'])
for P in [1, 2, 3, 5, 10]:
K, ck = fs_coef(P, T)
fs_plot[P] = hv.Spikes((K, P*ck), 'Frecuencia (k)', 'P x ck').opts(xlim=(-50, 50))
signal_plot[P] = hv.Curve((t, synthesis(t, ck, P)), 'Tiempo (segundos)', 'Señal')
(signal_plot+fs_plot)
De la figura tenemos que cuando P es grande (o equivalentemente f es pequeño)
el tren de pulsos tiende a un único pulso
los coeficientes toman una “forma suave”
Llamaremos a esta forma suave de \(P \cdot c_k\) la “envolvente” de los coeficientes. Si tomamos el caso \(P \to \infty\) la envolvente resultante es
o también
donde \(\omega = 2\pi f\) se llama frecuencia angular.
Nota
Esto se conoce como transformada de Fourier directa o integral de Fourier
Reemplazando \(c_k = f_0 S(k f_0)\) y tomando el límite cuando \(f_0 = \frac{1}{P} \to 0\) tenemos
o también
que se conoce como la transformada de Fourier inversa
2.3.2. Par de Fourier¶
Los operadores (transformada de Fourier directa)
y (transformada de Fourier inversa)
se conocen como par de Fourier y nos permiten analizar una señal en el dominio del tiempo o en el dominio de la frecuencia sin pérdidas
2.3.3. Ejemplo: Transformada del pulso cuadrado¶
Consideremos nuevamente el pulso cuadrado
su transformada de Fourier es
Esto calza precisamente con la “envolvente” que vimos anteriomente
T = 0.25
w = np.arange(-100, 100)
S = 2*np.sin(w*T)/w
S[w==0] = 0.5
<ipython-input-13-6be2a149569f>:4: RuntimeWarning: invalid value encountered in true_divide
S = 2*np.sin(w*T)/w
hv.Curve((w, S), 'Frecuencia angular', 'Espectro').opts(width=500)
2.3.4. Propiedades de la transformada de Fourier¶
La transformada de Fourier es un operador lineal, si tenemos dos señales y dos valores escalares entonces
El operador de convolución en el tiempo se convierte en multiplicación en frecuencia
donde
es la operación de convolución
Así mismo, la multiplicación en frecuencia se convierte en multiplicación en el tiempo
Finalmente el Teorema de Parseval nos dice que la energía se preserva entre frecuencia y tiempo
2.3.5. Definición: Espectros de amplitud y fase¶
Llamamos a \(S(\omega)\) el espectro (transformada de Fourier) de una señal \(s(t)\)
El espectro es un número complejo que podemos escribir en notación polar como
donde \(|S(\omega)|\) se conoce como espectro de amplitud y \(\Phi(\omega)\) como espectro de fase
2.4. Resumen de la lección¶
En esta lección aprendimos
a realizar síntesis de señales usando sinusoides
a descomponer señales periódicas usando la serie de Fourier
a descomponer señales periódicas y no periódicas usando la transformada de Fourier
2.5. Apéndice: Números complejos¶
Sea z un número complejo, lo podemos escribir en forma cartesiana
donde \(a \in \mathbb{R}\), \(b \in \mathbb{R}\) y \(j = \sqrt{-1}\) es el número imaginario.
También podemos escribirlo en forma polar
donde
\(c = |z| = \sqrt{a^2 + b^2} \in [0, \infty]\) es la magnitud
\(\phi = \angle z = \tan^{-1} \left (\frac{b}{a} \right) \in [-\frac{\pi}{2}, \frac{\pi}{2}]\) es el ángulo
\(a = c \cos(\phi)\)
\(b = c\sin(\phi)\)
se pueden escribir las siguientes relaciones
el complejo conjugado de \(z = a + j b = c e^{j\phi}\) es

